home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Medal Software 2
/
Gold Medal Software Volume 2 (Gold Medal) (1994).iso
/
graphics
/
povsrc20.arj
/
MACHINE
/
UNIX
/
XWIN.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-06
|
16KB
|
496 lines
/* From: kelvin@autodesk.com (John Walker)
* Message-Id: <9206091233.AA22915@throop>
* To: 73767.1244@uunet.uu.net
* Subject: Extensions to XWIN.C module of POV-Ray
* Attached is a modified version of the XWIN.C module included in the
* BETA 0.5 distribution of POV-Ray. While the display is still dithered for
* a monochrome screen (I, too, have only a monochrome monitor on my X
* machine), it now uses the Floyd-Steinberg error diffusion algorithm rather
* than a fixed 8x8 dithering matrix, which results in *much* better looking
* images. There is one slight drawback to this algorithm; it requires that
* you buffer an entire line of pixels before displaying them so the image
* now appears line-by-line rather that dot-by-dot. I don't find this
* objectionable, and it does concentrate the display update context switches
* into one burst rather than a steady drone.
* This code also includes optional gamma correction, which you can enable
* by defining the tag Gamma to the desired floating point value. If Gamma is
* undefined (as in the attached code), the gamma correction is entirely
* disabled.
* Thank you all for creating such a wonderful tool as POV-Ray. I hope this
* contribution proves useful.
*/
/*------------------------------------ Cut here ------------------------- xwin.c */
/****************************************************************************
* xwindows.c
*
* This module implements X-windows specific routines.
*
* from Persistence of Vision Raytracer
* Copyright 1993 Persistence of Vision Team
*---------------------------------------------------------------------------
* NOTICE: This source code file is provided so that users may experiment
* with enhancements to POV-Ray and to port the software to platforms other
* than those supported by the POV-Ray Team. There are strict rules under
* which you are permitted to use this file. The rules are in the file
* named POVLEGAL.DOC which should be distributed with this file. If
* POVLEGAL.DOC is not available or for more info please contact the POV-Ray
* Team Coordinator by leaving a message in CompuServe's Graphics Developer's
* Forum. The latest version of POV-Ray may be found there as well.
*
* This program is based on the popular DKB raytracer version 2.12.
* DKBTrace was originally written by David K. Buck.
* DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
*
*****************************************************************************/
/*
Here are some routines I wrote which implement +d option on
unix computers running X-windows. For now, only black
and white output is supported. If I get access to a computer
with a color monitor, I'll probably add support for colors to
my routines.
In future I'll probably add some more dithering methods.
I have tested these routines on SUN 3 and SUN 4. I'm using
the tvtwm window manager.
If you have some suggestions to my source code or if you change
anything, please let me know. I can be reached at the following
address: Marek Rzewuski, Avstikkeren 11, 1156 Oslo 11, Norway or
marekr@ifi.uio.no on Internet.
* * *
On 9th May 1992, I replaced the original 8x8 dithering matrix
in this module with Floyd-Steinberg error diffusion mapping of
the YIQ-derived grey scale into a monochrome bitmap. The
Floyd-Steinberg code was based on the algorithm used in the
"pgmtopbm" module of Jef Poskanzer's raster toolkit (PBMPLUS).
In addition, I added optional gamma correction (with a default
factor of 0.5), to darken the picture somewhat and increase
the level of perceived detail. The gamma correction is
disabled in the standard version, but you can turn it back on
by uncommenting the declaration of Gamma if you find it
improves the quality of the pictures you're making.
-- John Walker
Autodesk Neuchatel
Internet: kelvin@Autodesk.com
*/
#include <stdio.h>
#include <X11/Xlib.h> /* some Xlib stuff */
#include <X11/Xutil.h>
#include "theIcon"
#include "frame.h"
#include "povproto.h"
#define BORDER_WIDTH 2
#define EV_MASK (ButtonPressMask | \
KeyPressMask | \
ExposureMask | \
StructureNotifyMask)
Display *theDisplay;
int theScreen;
int theDepth;
unsigned long theBlackPixel;
unsigned long theWhitePixel;
XEvent theEvent;
Window theWindow, openWindow();
GC theGC;
unsigned char *bitmap; /* pointer to our picture bitmap */
unsigned char *bitmapPos; /* position to the last drawn pixel in our bitm
ap */
/* global POV-Ray variables */
extern FRAME Frame;
extern unsigned int Options;
extern char DisplayFormat;
extern int First_Line;
enum pixval { BLACK, WHITE };
/* #define Gamma 0.5 */ /* Screen gamma correction factor */
#define Fthreshold 0.5
static unsigned char *scrline;
#ifdef Gamma
static unsigned char gammamap[256];
#endif
static enum pixval *pixrow;
static long *thiserr, *nexterr, *temperr;
static long threshval, sum;
static int ncols; /* Screen width */
#define FS_SCALE 1024
#define HALF_FS_SCALE 512
static int fs_direction;
void unix_init_POVRAY PARAMS ((void))
{
}
/* Sets up a connection to the X server and stores informations about the envir
oment */
initX()
{
theDisplay = XOpenDisplay(NULL);
if (theDisplay == NULL) {
fprintf(stderr,"ERROR: Cannot establish a connection to the X server %s\n",
XDisplayName(NULL));
exit(1);
}
theScreen = DefaultScreen(theDisplay);
theDepth = DefaultDepth(theDisplay, theScreen);
theWhitePixel = WhitePixel(theDisplay, theScreen);
theBlackPixel = BlackPixel(theDisplay, theScreen);
}
/* This procedure will do the following things:
1) Set up attributes desired for the window
2) Set up an icon to our window.
3) Send hints to the window manager.
4) Open a window on the display
5) Tell the X to place the window on the screen
6) Flush out all the queued up X requests to the X server */
Window openWindow(x,y,width,height,flag,theNewGC)
int x,y;
int width,height;
int flag;
GC *theNewGC;
{
XSetWindowAttributes theWindowAttributes;
XSizeHints theSizeHints;
unsigned long theWindowMask;
Window theNewWindow;
Pixmap theIconPixmap;
XWMHints theWMHints;
/* Set up some attributes for the window. Override_redirect tells
the window manager to deal width the window or leave it alone */
theWindowAttributes.border_pixel = theBlackPixel;
theWindowAttributes.background_pixel = theWhitePixel;
theWindowAttributes.override_redirect = False;
theWindowMask = CWBackPixel | CWBorderPixel | CWOverrideRedirect;
/* Now, open out window */
theNewWindow = XCreateWindow(theDisplay,
RootWindow(theDisplay,theScreen),
x,y,
width, height,
BORDER_WIDTH,
theDepth,
InputOutput,
CopyFromParent,
theWindowMask,
&theWindowAttributes);
/* Create one iconbitmap */
theIconPixmap = XCreateBitmapFromData(theDisplay,
theNewWindow,
theIcon_bits,
theIcon_width,
theIcon_height);
/* Now tell the window manager where on screen we should place our
window. */
theWMHints.icon_pixmap = theIconPixmap;
theWMHints.initial_state = NormalState; /* we don't want an ico
nized window when it's created */
theWMHints.flags = IconPixmapHint | StateHint;
XSetWMHints(theDisplay,theNewWindow,&theWMHints);
theSizeHints.flags = PPosition | PSize;
theSizeHints.x = x;
theSizeHints.y = y;
theSizeHints.width = width;
theSizeHints.height = height;
/* theSizeHints.min_width = width;
theSizeHints.min_height = height;
theSizeHints.max_width = width;
theSizeHints.max_height = height; */
XSetNormalHints(theDisplay,theNewWindow,&theSizeHints);
if (createGC(theNewWindow, theNewGC) == 0) {
XDestroyWindow(theDisplay, theNewWindow);
return((Window) 0);
}
/* Make a name for our window */
XStoreName(theDisplay, theNewWindow, "Persistence Of Vision Raytracer\0");
/* Now, could we please see the window on the screen?
Until now, we have dealt with a window which has been created
but not appeared on the screen. Maping the window places it visibly
on the screen */
XMapWindow(theDisplay,theNewWindow);
XFlush(theDisplay);
return(theNewWindow);
}
refreshWindow(theExposedWindow)
Window theExposedWindow;
{
int i, x, y;
unsigned char *dummy;
dummy = bitmap;
i = 0; x= 0; y = First_Line;
while (dummy < bitmapPos) {
if (*dummy)
XDrawPoint(theDisplay, theWindow, theGC,x,y);
if (x == Frame.Screen_Width) {
x = 0;
y++;
} else {
dummy++;
x++;
i++;
}
}
XFlush(theDisplay);
}
/* Creates a new graphics context */
createGC(theNewWindow, theNewGC)
Window theNewWindow;
GC *theNewGC;
{
XGCValues theGCValues;
*theNewGC = XCreateGC(theDisplay,
theNewWindow,
(unsigned long) 0,
&theGCValues);
if (*theNewGC == 0) {
return(0); /*error*/
} else { /* set foreground and background defaults for the new GC */
XSetForeground(theDisplay,
*theNewGC,
theBlackPixel);
XSetBackground(theDisplay,
*theNewGC,
theWhitePixel);
return(1); /* OK */
}
}
initEvents(theWindow)
Window theWindow;
{
XSelectInput(theDisplay,
theWindow,
EV_MASK);
}
void display_finished ()
{
}
void display_init ()
{
int i;
int cols;
/* Allocate error propagation vectors for Floyd-Steinberg algorithm. */
ncols = Frame.Screen_Width;
cols = ncols + 2;
scrline = (unsigned char *) malloc(ncols * sizeof(unsigned char));
pixrow = (enum pixval *) malloc(ncols * sizeof(enum pixval));
thiserr = (long *) malloc(cols * sizeof(long));
nexterr = (long *) malloc(cols * sizeof(long));
if (scrline == NULL || pixrow == NULL ||
thiserr == NULL || nexterr == NULL) {
printf("XWIN error: Failed to allocate Floyd-Steinberg error vectors.\n");
exit(0);
}
srandom((int) (time(NULL) ^ getpid()));
/* (Random errors in [-FS_SCALE/8 .. FS_SCALE/8]) */
for (i = 0; i < cols; i++) {
thiserr[i] = (random() % FS_SCALE - HALF_FS_SCALE) / 4;
}
fs_direction = 1;
threshval = Fthreshold * FS_SCALE;
/* Initialise gamma correction table. */
#ifdef Gamma
for (i = 0; i < 256; i++) {
int gc = 255.0 * pow((((double) i) / 255.0), (1.0 / Gamma)) + 0.5;
gammamap[i] = (gc > 255) ? 255 : gc;
}
#endif
/* Set some room for a bitmap for our picture. I've got to
"remember" the whole picture because of resizing of the window,
overlapping etc. Then I've got to refresh the picture. This
should be easy to convert to an "color version" in future */
bitmap = (unsigned char *) malloc(sizeof(unsigned char) *
(Frame.Screen_Width * Frame.Screen_Height));
bitmapPos = bitmap;
if (bitmap == NULL) {
printf("XWIN error: Can not allocate the buffer..\n");
exit(0);
}
for (i = 0; i < (Frame.Screen_Width*Frame.Screen_Height); i++) {
*bitmapPos++ = 0;
}
bitmapPos = bitmap;
initX();
theWindow = openWindow(0,0,Frame.Screen_Width,Frame.Screen_Height,0,&theGC);
initEvents(theWindow);
XFlush(theDisplay);
#ifdef NEEDED
/* On my Sun SPARCStation 2 running OpenWindows 3.0, this XNextEvent call
sometimes makes the window go to sleep until some event is artificially
generated for it (for example, by clicking the mouse in it). I removed
the call and everything seems to work just fine. -- JW */
XNextEvent(theDisplay,&theEvent);
XFlush(theDisplay);
#endif
} /* end of display initialisation */
void display_close ()
{
sleep(10); /* an simple delay. 10 seconds. */
XDestroyWindow(theDisplay,theWindow);
XFlush(theDisplay);
XCloseDisplay(theDisplay);
free(bitmap);
}
void display_plot (x, y, Red, Green, Blue)
int x, y;
unsigned char Red, Green, Blue;
{
int numEvents;
/* lets find if there are some events waiting for us */
numEvents = XPending(theDisplay);
if (numEvents > 0) { /* now deal with the events.. */
XNextEvent(theDisplay,&theEvent);
switch (theEvent.type) {
case Expose:
/*printf("Window is exposed.\n");*/
refreshWindow(theEvent.xany.window);
break;
case MapNotify:
/*printf("The window is mapped.\n");*/
refreshWindow(theEvent.xany.window);
break;
case ButtonPress:
/*printf("A mouse button was pressed.\n");*/
break;
case ConfigureNotify:
/*printf("The window configuration has been changed\n");*/
refreshWindow(theEvent.xany.window);
break;
}
}
scrline[x] =
#ifdef Gamma
gammamap[
#endif
(int) (0.299 * Red + 0.587 * Green + 0.114 * Blue)
#ifdef Gamma
]
#endif
;
if (x >= (ncols - 1)) {
int col, limitcol;
unsigned char *pixelp; /* Grey scale pixel pointer */
enum pixval *bitmapp; /* Monochrome bitmap pointer */
for (col = 0; col < ncols + 2; ++col) {
nexterr[col] = 0;
}
if (fs_direction) {
col = 0;
limitcol = ncols;
pixelp = scrline;
bitmapp = pixrow;
} else {
col = ncols - 1;
limitcol = -1;
pixelp = &(scrline[col]);
bitmapp = &(pixrow[col]);
}
do {
sum = ((long) *pixelp * FS_SCALE) / 255 + thiserr[col + 1];
if (sum >= threshval) {
*bitmapp = WHITE;
sum = sum - threshval - HALF_FS_SCALE;
} else {
*bitmapp = BLACK;
}
if (fs_direction) {
thiserr[col + 2] += (sum * 7) / 16;
nexterr[col ] += (sum * 3) / 16;
nexterr[col + 1] += (sum * 5) / 16;
nexterr[col + 2] += (sum ) / 16;
++col;
++pixelp;
++bitmapp;
} else {
thiserr[col ] += (sum * 7) / 16;
nexterr[col + 2] += (sum * 3) / 16;
nexterr[col + 1] += (sum * 5) / 16;
nexterr[col ] += (sum ) / 16;
--col;
--pixelp;
--bitmapp;
}
} while (col != limitcol);
temperr = thiserr; /* Swap error vectors */
thiserr = nexterr;
nexterr = temperr;
fs_direction = ! fs_direction;
for (col = 0; col < ncols; col++) {
*bitmapPos++ = !pixrow[col];
if (!pixrow[col]) {
XDrawPoint(theDisplay, theWindow, theGC, col, y);
}
}
}
/*XFlush(theDisplay); Let's be nice to the network, OK? */
}